package com.qmds.userserver.user.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.qmds.common.baidu.utils.BaiduUtil;
import com.qmds.common.core.config.RedisKeyConfig;
import com.qmds.common.core.entity.SmsLog;
import com.qmds.common.core.entity.User;
import com.qmds.common.core.entity.UserLog;
import com.qmds.common.core.param.PhoneCode;
import com.qmds.common.core.param.UserFindPwd;
import com.qmds.common.core.vo.R;
import com.qmds.userserver.user.dao.SmsLogMapper;
import com.qmds.userserver.user.dao.UserLogMapper;
import com.qmds.userserver.user.dao.UserMapper;
import com.qmds.userserver.user.param.UpdateByIdParam;
import com.qmds.userserver.user.service.UserService;
import com.qmds.userserver.user.sms.AliSmsUtil;
import com.qmds.userserver.user.vo.PeopleVo;
import com.qmds.userserver.user.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * --- 天道酬勤 ---
 *
 * @author zhanghanxuan
 * @date 2024/9/9
 * @desc
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private BaiduUtil baiduUtil;

    @Resource
    private  StringRedisTemplate template;

    private final SmsLogMapper smsLogMapper;
    private final UserLogMapper userLogMapper;

    public UserServiceImpl(SmsLogMapper smsLogMapper, UserLogMapper userLogMapper) {
        this.smsLogMapper = smsLogMapper;
        this.userLogMapper = userLogMapper;
    }


    @Override
    public PeopleVo my(Integer id) {
        User user = userMapper.selectById(id);
        PeopleVo people = new PeopleVo();
        BeanUtils.copyProperties(user,people);
        return people;
    }

    @Override
    // @Transactional
    public List<PeopleVo> findAll(IPage<PeopleVo> page, HashMap<String, String> map) {
        Integer s = null;
        if(map.get("type")!=null){
            s = Integer.valueOf(map.get("type"));
        }
        return userMapper.findAll(page,s);
    }

    @Override
    public R addUser(UserVo userVo) {
        String s = String.valueOf(userVo.getPhone());
        String i = String.valueOf(userVo.getIdCard());
        if (s.equals(userMapper.selectPhone(s))){
            return R.ok("该手机号已注册");
        }
        if (i.equals(userMapper.selectIdCard(i))){
            return R.fail("该身份证已经被使用");
        }

        int  checkFlag = baiduUtil.textCheck(userVo.getAvatar());
        if (checkFlag==2){
            throw new RuntimeException("图片违规");
        }
        return R.ok(userMapper.addUser(userVo));
    }

    @Override
    public boolean updateUser(UserVo userVo) {

        String idCard = userVo.getIdCard();
        String phone = userVo.getPhone();
        if (userMapper.selectIdCard(idCard)!= null || userMapper.selectPhone(phone)!= null){
            return false;
        }
        return userMapper.updateUser(userVo);
    }

    @Override
    public List<Integer> getType() {
        return userMapper.getType();
    }
    @Override
    public R<List<Map<String, Object>>> getEcharts(Integer type) {
        List<Map<String, Object>> statusForCharts = userMapper.getEcharts(type);
        List<Map<String, Object>> list = new ArrayList<>();
        AtomicLong total = new AtomicLong(0L);
        System.out.println(total);

        statusForCharts.forEach(item -> {
            Integer status = (Integer) item.get("type");
            Object num = item.get("val");
            Map<String, Object> maps= new HashMap<>();
            if (status == 1) {
                maps.put("name", "系统人员");
                maps.put("value", num);
                total.addAndGet((Long) num);
            } else if (status == 2){
                maps.put("name", "企业人员");
                maps.put("value", num);
                total.addAndGet((Long) num);
            }else if (status == 3) {
                maps.put("name", "备案人员");
                maps.put("value", num);
                total.addAndGet((Long) num);
            } else if (status == 4) {
                maps.put("name", "禁用人员");
                maps.put("value", num);
                total.addAndGet((Long) num);
            }

            list.add(maps);
        });

        list.add(0, new HashMap<String, Object>(){
            {
                put("name", "所有人员");
                put("value", total);
            }
        });

        return R.ok(list);
    }
    @Override
    public R checkPhone(String phone) {
        //1.校验 非空 手机号格式-正则
        if(StringUtils.hasLength(phone))
        {
            //2.查询 验证手机号是否存在 不存在-可用
            if(userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone,phone))==null){
                //可用
                return R.ok("");
            }
        }
        return R.fail("亲，请您检查手机号！");
    }



    @Override
    public R sendRcode(String phone) {
        //1.校验
        if(StringUtils.hasLength(phone)){
            //2.手机号 不存在
            if(userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone,phone))==null){
                //3.生成验证码
                String code= RandomUtil.randomNumbers(6);
                log.error("注册验证码={}",code); //记录日志
                //4.发送短信
                if(AliSmsUtil.sendCode(AliSmsUtil.TEM_RCODE,phone,code)){
                    //5 存储验证码 使用Redis
                    //五问：1.为什么使用 2.使用哪种数据类型 3.要不要设置有效期 4.存储什么样的内容 5.要不要考虑数据同步
                    //1.快 有效期 2.String 单个 3.要 10分钟 4.key cp:sms:code:手机号 value 验证码 5.不需要
                    template.opsForValue().set(RedisKeyConfig.KEY_RCODE+phone,code, RedisKeyConfig.CODE_TIME, TimeUnit.MINUTES);

                    //6.记录短信发送
                    smsLogMapper.insert(new SmsLog(phone,"注册验证码","实现注册验证码的发送"));

                    //移除验证码
                    template.delete(RedisKeyConfig.KEY_RCODE+phone);

                    //7.返回
                    return R.ok("请，查看手机");
                }
            }else if (userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone,phone))!=null){
                //3.生成验证码
                String code= RandomUtil.randomNumbers(6);
                log.error("重置密码验证码={}",code); //记录日志
                //4.发送短信
                if(AliSmsUtil.sendCode(AliSmsUtil.TEM_RCODE,phone,code)){
                    //5 存储验证码 使用Redis
                    //五问：1.为什么使用 2.使用哪种数据类型 3.要不要设置有效期 4.存储什么样的内容 5.要不要考虑数据同步
                    //1.快 有效期 2.String 单个 3.要 10分钟 4.key cp:sms:code:手机号 value 验证码 5.不需要
                    template.opsForValue().set(RedisKeyConfig.KEY_RCODE+phone,code, RedisKeyConfig.CODE_TIME, TimeUnit.MINUTES);

                    //6.记录短信发送
                    smsLogMapper.insert(new SmsLog(phone,"重置密码验证码","实现重置密码验证码的发送"));

                    //移除验证码
                    template.delete(RedisKeyConfig.KEY_RCODE+phone);

                    //7.返回
                    return R.ok("请，查看手机");
                }
            }
        }
        return R.fail("亲，请检查手机号！");
    }

    @Override
    public R checkRcode(PhoneCode phoneCode) {
        //1.验证是否存在
        String key = RedisKeyConfig.KEY_RCODE+phoneCode.getPhone();
        if(template.hasKey(key)){
            //2.比较验证码
            if (Objects.equals(phoneCode.getCode(), template.opsForValue().get(key))) {
                //3.验证码比对成功 删除验证码
                template.delete(key);

                //4.记录验证通过 的手机号
                template.opsForSet().add(RedisKeyConfig.KEY_RPHONES,phoneCode.getPhone());

                return R.ok("");
            }
        }
        return R.fail("亲，验证码无效！");
    }

    @Override
    public R findPwd(UserFindPwd pwd) {
        if (pwd == null){
            return R.fail("亲，请检查参数！");
        }

        //2.校验注册手机号 有没有校验过验证码
        if(!template.opsForSet().isMember(RedisKeyConfig.KEY_RPHONES,pwd.getPhone())) {
            return  R.fail("亲，请完成验证码校验");
        }
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, pwd.getPhone()));//获取用户信息
        // user.setPassword(SecureUtil.sha1(SecureUtil.md5(user.getPassword())));//密码加密
        userMapper.update(new LambdaUpdateWrapper<User>().set(User::getPassword,pwd.getPassword()).eq(User::getId,user.getId()));
        //7.记录日志
        userLogMapper.insert(new UserLog(user.getId(),"找回","找回密码","找回密码成功"));
        //8.返回信息
        return R.ok("密码更新成功");
    }

    @Override
    public R updateById(UpdateByIdParam updateByIdParam) {
        if (updateByIdParam.getId() == null){
            return R.fail("亲，请检查参数！");
        }
        return R.ok(userMapper.updateById(updateByIdParam));
    }
}
